#ifndef BUST_ANY_H
#define BUST_ANY_H

#include <typeinfo>
#include <exception>

namespace bust {
namespace {

class BadAnyCast: public std::exception {
	public:
		const char* what() throw() {
			return "Bad cast of bust::any.";
		}
};

class any {
	public:
		any() :
			content( 0 ) {
		}
		template < class T >
		any( const T& o ) :
			content( new holder< T > ( o ) ) {
		}
		any( const any& rhs ) :
			content( rhs.content ? rhs.content->clone() : 0 ) {
		}
		any& swap( any& rhs ) {
			any tmp = rhs;
			rhs = *this;
			*this = tmp;
			return *this;
		}
		template < class T >
		any& operator=( const T& rhs ) {
			any( rhs ).swap( *this );
			return *this;
		}
		any& operator=( any& rhs ) {
			rhs.swap( *this );
			return *this;
		}
		bool empty() const {
			return !content;
		}
		const std::type_info& type() const {
			return content ? content->type() : typeid(void);
		}
		template < class T >
		T* getPtr() {
			return this && this->type() == typeid(T) ? &static_cast< holder< T >* > ( content )->held
					: 0;
		}
		template < class T >
		const T* getPtr() const {
			return this && this->type() == typeid(T) ? &static_cast< holder< T >* > ( content )->held
					: 0;
		}
		template < class T >
		T& get() {
			T* ptr = getPtr< T > ();
			if( !ptr )
				throw BadAnyCast();
			return *ptr;
		}
	private:
		class placeholder {
			public:
				virtual ~placeholder() {
				}

				virtual const std::type_info& type() const = 0;
				virtual placeholder* clone() const = 0;
		};
		template < class T >
		class holder: public placeholder {
			public:
				holder( const T& o ) :
					held( o ) {
				}

				const std::type_info& type() const {
					return typeid(T);
				}
				placeholder* clone() const {
					return new holder( held );
				}

				T held;
		};
	private:
		placeholder *content;
};

}
}

#endif
